/**
 * This class acts ass query operator.
 * It takes in the array that contains Database name, collection name, 
 * Action and the query.
 * @author FATIMA ALKHARROBI
 *	@author Camaria Bevavy
 */
package com.mongoproject.database;
import com.mongodb.Mongo;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.util.JSON;

import java.io.File;
import java.net.UnknownHostException;
import java.util.ArrayList; 
import java.util.Map;


public class QueryProcesser {

	static DBCollection items = null; 
	static Mongo mongo = null;
	static DB db=null;
    static ArrayList<DBObject>object_list;
    static ArrayList<String> arrList = new ArrayList<String>();
    boolean flag ; 
	
    /**
     * constructor
     * @param list: contains query and collection name
     */
	public QueryProcesser(ArrayList<String> list){
		 flag = false ; 
		 arrList = list;
	}

   	/**
   	 * perform insert, update, delete, select query to the database
   	 * @return string result
   	 * @throws UnknownHostException
   	 */
	public String performQuery ( ) throws UnknownHostException { 
		String result = "" ;
		object_list = new ArrayList<DBObject>() ;

	    //create db and collection
	    mongo = new Mongo();
	    db = mongo.getDB( arrList.get(0) );
        items = db.getCollection( arrList.get(1) );
	    // insert() query 
	    if ( arrList.get(2).equals("Insert") ) {
	    	//System.out.println("Entering Insert");
		    insertFunction(arrList.get(3)); 
		    }
		else if ( arrList.get(2).equals( "Find") ){
			//System.out.println("Entering Find");
			result = findFunction(arrList.get(3)); 
		}
		    
		else if ( arrList.get(2).equals ("Update") )
		{
			//System.out.println("Entering Update");
			result = updateFunction(arrList.get(3)); 
		}
		else if ( arrList.get(2).equals( "Delete" ))  
		{
			//System.out.println("Entering Delete");
            result = removeFunction(arrList.get(3));
		}
		else if( arrList.get(2).equals( "Generate" )){

			Data_Script ds=new Data_Script();

			ds.generateData(arrList.get(0), arrList.get(1));

			}
		else{
			System.out.println("Something werird");
		}
	    
	    return result;
	}
	
	/**
	 *  Insert the query into the database.
	 * @param String of query
	 */
	public void insertFunction (String a) {
		
		String json = a;
	    DBObject query = (DBObject)JSON.parse(json);
        items.insert(query);
       
        updateViews(items.toString());
        
	} 
		
	/**
	 * Find the query from the database.
	 * @param String of query
	 * @return string message
	 */ 
	public String findFunction (String a){
		String result = "";
		ViewMetadata metafile = new ViewMetadata();
		String viewfilename = metafile.findViewMeta(arrList.get(1), arrList.get(3));
		
		//System.out.println("viewfilename " + viewfilename);
	
		if(viewfilename != null){
			XmlReader read = new XmlReader();
			result = read.readXMLFile(viewfilename, arrList.get(1));
		}
		else{
			result = dbFind(a);
		}
		
		return result;
	}
	
	/**
	 * query inside database and return result
	 * @param a: string query
	 * @return result of query
	 */
	public String dbFind(String a){
		String result = "";
		
		if(!object_list.isEmpty()){
			object_list.clear();
		}
		
        String json = a;
	   
	    try{
		    	
		    	DBObject query = (DBObject)JSON.parse(json);
		    	DBCursor cursor = items.find(query);
		    	while (cursor.hasNext()) {
				   	DBObject obj = cursor.next(); 
	                object_list.add(obj);
	                result += obj.toString();
	               
	        } 
	    }
	    catch(Exception ex){
	    	System.out.println(ex.getMessage());
	    }
	    
        String collName= items.toString();
       
        String filename = createView(collName); //create view
        
        logMeta(filename, a); //update meta
        
        return result;
	}
	
	/**
	 * update the query from the database.
	 * @param String of query
	 * @return string message response
	 */
    public String updateFunction(String a) { 
    	String result = "";
		String json = a;
	    DBObject updateQuery = (DBObject)JSON.parse(json);
        DBCursor cursor = items.find(updateQuery);
        
        if(cursor.count() > 0){
	        if(cursor.hasNext()) {
	            DBObject updatedItem = cursor.next();
	            items.save(updatedItem);
	            flag = true ; 
	        }
	        updateViews(items.toString());
        }
        else{
        	result = "Item does not exist.";
        }
 
        return result;
    }	
	    
    /**
	 * delete the query from the database.
	 * @param String of query
	 * @return string message
	 */
    public String removeFunction (String a)  { 
    	String result = "";
		String json = a;
	    DBObject deleteQuery = (DBObject)JSON.parse(json);
        DBCursor cursor = items.find(deleteQuery);
        if(cursor.count() > 0){
	        while (cursor.hasNext()) {
	            DBObject item = cursor.next();
	            items.remove(item);
	        }
	        updateViews(items.toString());
        }
        else{
        	result = "Item does not exist.";
        }
        
        
        return result;
	}
	/**
	 * get the list of query results
	 * @return query result
	 */
	public ArrayList<DBObject> getObjectList () {
	    return object_list ; 
	}

	/**
	 * update any view that uses this collection
	 * @param collectionName: name of database collection
	 */
	public void updateViews(String collectionName){
		ViewMetadata v = new ViewMetadata();
		Map<String,String> map = v.findCollectionMeta(collectionName);
		
		if(!map.isEmpty()){
			for(Map.Entry<String,String> entry : map.entrySet()){
				String filename = entry.getKey();
				String query = entry.getValue();
				
				//update meta by removing the reference to filename
				v.deleteMeta(filename);
				
				//delete filename;
				File f = new File(filename);
				f.delete();
				
				dbFind(query); //build new xml view and update metadata

			}
		}
		else{
			System.out.println("nothing to delete");
		}
	
	}

	/**
	 * method that calls the XML builder class to create a view 
	 * @param collName: name of the database collection
	 * @return xml filename
	 */
	public String createView(String collName){
		String filename = null;
		
		if(!object_list.isEmpty()){
			XmlBuilder xml=new XmlBuilder(collName);
	        
	        filename = xml.xmlBuild(object_list);
		}

        return filename;
	}
	
	/**
	 * update the view metadata
	 * @param filename: xml filename
	 * @param query: query used to create the view
	 */
	public void logMeta(String filename, String query){
		 //update metadata
		if(filename != null){
	        ViewMetadata meta = new ViewMetadata();
	        meta.insertMeta(arrList.get(1), query, filename);
		}
	}
	
	
}